package com.pig.easy.bpm.generator;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * todo:
 *
 * @author : pig
 * @date : 2020/5/12 19:49
 */
public class MybaticPlusGenerator {

    /**
     * 数据库地址 记得修改
     */
//    public static String DB_URL = "jdbc:mysql://IP:端口/数据库名称?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull";
    public static String DB_URL = "jdbc:mysql://120.77.218.141:3306/easy_bpm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull";

    /**
     * 数据库用户
     */
//    public static String USER = "数据库用户名称";
    public static String USER = "root";

    /**
     * 数据库密码
     */
   // public static String PASSWORD = "用户卡用户密码";
    public static String PASSWORD = "123456";

    /**
     * 参与逆向工程的表名
     **/
    public static String[] INCLUDE_TABLE_NAMES = new String[]{"bpm_message_content","bpm_message_white_list"};
    /**
     * 不参与逆向工程的表名
     **/
    public static String[] EXCLUDE_TABLE_NAMES = new String[]{""};
    /**
     * 表id，用哪一种生成策略，如下面用的是分布式全局唯一ID，是不是分布式暂时没考就哈
     */
    public static IdType TABLE_ID_TYPE = IdType.AUTO;
    /**
     * 是否去掉生成实体的属性名前缀,如表有t_table1,m_table2，则这个值可以为 = new String[]{"t","m"}
     */

    public static String[] FIELD_PREFIX = new String[]{"bpm"};
    private static String BASE_MODULE_NAME = "bpm";
    public static final String TABLE_PREFIX = "bpm_";

    public static final String SUPER_SERVICE_CLASS = "com.pig.easy.bpm.service.impl.BeseServiceImpl";
    public static final String SUPER_CONTROLLER_CLASS = "com.pig.easy.bpm.controller.BaseController";
    /**
     * 项目存储位置
     */
    public static String PROJECT_GENERATE_DISK = System.getProperty("user.dir") + "/src/main/java";
    public static String WEB_PROJECT_GENERATE_DISK = System.getProperty("user.dir") + "/easy-"+ BASE_MODULE_NAME + "-web";
    public static String PROVIDER_PROJECT_GENERATE_DISK = System.getProperty("user.dir") + "/easy-"+ BASE_MODULE_NAME + "-provider";
    public static String INTERFACE_PROJECT_GENERATE_DISK = System.getProperty("user.dir") + "/easy-"+ BASE_MODULE_NAME + "-interface";
    public static String PARENT_PACKAGE = "com/pig/easy/"+ BASE_MODULE_NAME;
    public static String PARENT_PACKAGE_TEMP = "com.pig.easy." + BASE_MODULE_NAME;

    public static String DTO_RESPONSE = PARENT_PACKAGE_TEMP + ".dto.response";
    public static String DTO_REQUEST = PARENT_PACKAGE_TEMP + ".dto.request";
    public static String VO_REQUEST = PARENT_PACKAGE_TEMP + ".vo.request";
    /**
     * 数据库驱动名
     */
    public static String DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";
    /**
     * 数据库类型
     */
    public static String DB_TYPE = DbType.MYSQL.name();


    /**
     * 创建人
     */
    public static String AUTHOR = "pig";
    /**
     * 表字段生成对应的实体类时，字段属性是否需要强制带上注解
     */
    public static boolean ENABLE_TABLE_FIELD_ANNOTATION = false;


    /**
     * 全局配置
     *
     * @return
     */
    private static GlobalConfig GlobalGenerate() {
        GlobalConfig config = new GlobalConfig();
        /*不需要ActiveRecord特性的请改为false*/
        config.setActiveRecord(false)
                .setIdType(TABLE_ID_TYPE)
                /*是否启用二级缓存*/
                .setEnableCache(false)

                .setSwagger2(true)
                .setBaseResultMap(true)
                /*设置作者*/
                .setAuthor(AUTHOR)
                /*生成完之后，不弹窗，告知我在生成在哪个目录了*/
                .setOpen(false)
                /*XML 设置映射结果 ResultMap*/
                .setBaseResultMap(true)

                /*XML 设置表列 ColumnList*/
                .setBaseColumnList(true)
                /*设置生产的文件（包）在哪，一般是相对于本项目而言*/
                .setOutputDir(PROJECT_GENERATE_DISK)
                /*每次生成，是否覆盖之前的文件（慎重考虑啊）*/
                .setFileOverride(false)
                /*自定义文件命名，注意 %s 会自动填充表实体属性！*/
                .setControllerName("%sController")
                .setServiceName("%sService")
                .setServiceImplName("%sServiceImpl")
                .setEntityName("%s")
                .setMapperName("%sMapper")
                .setXmlName("%sMapper");

        return config;
    }

    /**
     * 数据源配置
     *
     * @return
     */
    private static DataSourceConfig DaoSourceGenerate() {
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        DbType type = null;
        if ("oracle".equals(DB_TYPE)) {
            type = DbType.ORACLE;
        } else if ("sql_server".equals(DB_TYPE)) {
            type = DbType.SQL_SERVER;
        } else if ("mysql".equals(DB_TYPE)) {
            type = DbType.MYSQL;
        } else if ("postgre_sql".equals(DB_TYPE)) {
            type = DbType.POSTGRE_SQL;
        }
        /*设置数据库类型*/
        dataSourceConfig.setDbType(type)
                /*设置数据库驱动（反射，基于类名，找到对应的类）*/
                .setDriverName(DRIVER_CLASS_NAME)
                /*设置数据库连接地址，地址包含库ip、端口、库名等*/
                .setUrl(DB_URL)
                /*设置数据库用户名*/
                .setUsername(USER)
                /*设置数据库密码*/
                .setPassword(PASSWORD);
        return dataSourceConfig;
    }

    /**
     * 策略配置
     *
     * @return
     */
    private static StrategyConfig StrategyGenerate() {
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig
                .setVersionFieldName("version")
                /*全局大写命名 ORACLE 注意*/
                .setCapitalMode(true)
                /*生成RestController*/
                .setRestControllerStyle(true)
                /*是否使用Lombok省略getter、setter*/
                .setEntityLombokModel(false)
//                .setDbColumnUnderline(true)
                /*表名生成策略 -- 驼峰*/
                .setNaming(NamingStrategy.underline_to_camel)
                // .setEntityTableFieldAnnotationEnable(ENABLE_TABLE_FIELD_ANNOTATION)
                /* 生成指定的xxxController、、xxService等是否去掉数据库表名的前缀，如t_user -> user -> UserController*/
                .setFieldPrefix(FIELD_PREFIX)
                /*设置哪些表参与逆向工程，多个表名传数组*/
                .setInclude(INCLUDE_TABLE_NAMES)
                /*设置哪些表不参与逆向工程，多个表名传数组；注意，不能和Include一起使用*/
//                .setExclude(EXCLUDE_TABLE_NAMES)
                /*此处可以修改为您的表前缀*/
                .setTablePrefix(null)
                /*自定义实体，公共字段*/
                .setSuperEntityColumns(null)
                /*自定义 mapper 父类*/
                .setSuperMapperClass(null)
                /*自定义 service 父类*/
                .setSuperServiceClass(null)
                /*自定义 controller 父类*/
                .setSuperControllerClass(null)
                /*【实体】是否生成字段常量（默认 false）public static final String ID = "test_id";*/
                .setEntityColumnConstant(false)//
                /*【实体】是否为构建者模型（默认 false）public User setName(String name) {this.name = name; return this;}*/
                .setEntityBuilderModel(true)
                /*【实体】是否为lombok模型（默认 false）*/
                .setEntityLombokModel(true)
                .setTablePrefix(TABLE_PREFIX)
                /*Boolean类型字段是否移除is前缀处理*/
                .setEntityBooleanColumnRemoveIsPrefix(true);

        if (!StringUtils.isEmpty(SUPER_SERVICE_CLASS)) {
            /*自定义 serviceImpl 父类*/
            strategyConfig.setSuperServiceImplClass(SUPER_SERVICE_CLASS);
        }
        if (!StringUtils.isEmpty(SUPER_CONTROLLER_CLASS)) {
            /*自定义 serviceImpl 父类*/
            strategyConfig.setSuperControllerClass(SUPER_CONTROLLER_CLASS);
        }

        return strategyConfig;
    }

    /**
     * 自定义模板配置
     *
     * @return
     */
    private static TemplateConfig templateGenerate() {
        return new TemplateConfig()
                // 置空后方便使用自定义输出位置
                .setEntity(null)
                .setXml(null)
                .setMapper(null)
                .setService(null)
                .setServiceImpl(null)
                .setController(null);

    }

    public static PackageConfig PackageGenerate() {
        PackageConfig pc = new PackageConfig()
                .setParent(PARENT_PACKAGE_TEMP)
                .setController("controller")
                .setService("service")
                .setServiceImpl("service.impl")
                .setEntity("entity")
                .setMapper("mapper")
                .setXml("mapper");
        return pc;
    }

    public static InjectionConfig createInjectionConfig() {
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // 可看作设置了几个全局量，在模板中的使用方法${cfg.dtoResponse}
                Map<String, Object> map = new HashMap<>();
                map.put("dtoResponse", DTO_RESPONSE);
                map.put("dtoRequest", DTO_REQUEST);
                map.put("voRequest", VO_REQUEST);
                this.setMap(map);
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return PROVIDER_PROJECT_GENERATE_DISK + "/src/main/resources/mapper"
                        + "/" + tableInfo.getMapperName() + ".xml";
            }
        });
        focList.add(new FileOutConfig("/templates/service.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return INTERFACE_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/service"
                        + "/" + tableInfo.getServiceName() + ".java";
            }
        });

        focList.add(new FileOutConfig("/templates/mapper.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return PROVIDER_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/mapper"
                        + "/" + tableInfo.getMapperName() + ".java";
            }
        });

        focList.add(new FileOutConfig("/templates/serviceImpl.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return PROVIDER_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/service/impl"
                        + "/" + tableInfo.getServiceImplName() + ".java";
            }
        });

        focList.add(new FileOutConfig("/templates/entity.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return PROVIDER_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/entity"
                        + "/" + tableInfo.getEntityName() + "DO.java";
            }
        });

        focList.add(new FileOutConfig("/templates/controller.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return WEB_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/controller"
                        + "/" + tableInfo.getControllerName() + ".java";
            }
        });

        focList.add(new FileOutConfig("/templates/controller.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return WEB_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/controller"
                        + "/" + tableInfo.getControllerName() + ".java";
            }
        });
        cfg.setFileOutConfigList(focList);

        focList.add(new FileOutConfig("/templates/queryVO.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return WEB_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/vo/request"
                        + "/" + tableInfo.getEntityName() + "QueryVO.java";
            }
        });


        focList.add(new FileOutConfig("/templates/saveOrUpdateVO.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return WEB_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/vo/request"
                        + "/" + tableInfo.getEntityName() + "SaveOrUpdateVO.java";
            }
        });


        focList.add(new FileOutConfig("/templates/queryDTO.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return INTERFACE_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/dto/request"
                        + "/" + tableInfo.getEntityName() + "QueryDTO.java";
            }
        });


        focList.add(new FileOutConfig("/templates/saveOrUpdateDTO.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return INTERFACE_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/dto/request"
                        + "/" + tableInfo.getEntityName() + "SaveOrUpdateDTO.java";
            }
        });
        

        focList.add(new FileOutConfig("/templates/baseDTO.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return INTERFACE_PROJECT_GENERATE_DISK + "/src/main/java/" + PARENT_PACKAGE + "/dto/response"
                        + "/" + tableInfo.getEntityName() + "DTO.java";
            }
        });
        cfg.setFileOutConfigList(focList);

        return cfg;
    }

    public void generateByTablesWithInjectConfig() {
        //全局配置
        GlobalConfig config = MybaticPlusGenerator.GlobalGenerate();
        //配置数据源
        DataSourceConfig dataSourceConfig = MybaticPlusGenerator.DaoSourceGenerate();
        //配置策略
        StrategyConfig strategyConfig = MybaticPlusGenerator.StrategyGenerate();
        //配置包
        PackageConfig packageConfig = MybaticPlusGenerator.PackageGenerate();

        InjectionConfig injectionConfig = MybaticPlusGenerator.createInjectionConfig();
        TemplateConfig templateConfig = templateGenerate();

        //生成代码
        new AutoGenerator()
                .setGlobalConfig(config)
                .setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig)
                .setPackageInfo(packageConfig)
                .setCfg(injectionConfig)
                // 因为使用了自定义模板,所以需要把各项置空否则会多生成一次
                .setTemplate(templateConfig)
                .execute();
    }

    public static void main(String[] args) {

        // System.out.println("System.getProperty(\"user.dir\") = " + System.getProperty("user.dir"));

        MybaticPlusGenerator generatorServiceEntity = new MybaticPlusGenerator();
        generatorServiceEntity.generateByTablesWithInjectConfig();
    }


}
